package haxeframe;

// import flash.display.StageOrientation;
import flash.net.SharedObject;

import haxeframe.utils.MathUtils;
import haxeframe.utils.Utils;

class Globals
{
	public static var PRECISION:Float = 100;
	
	public static var ASPECT_RATIO_16x9:Float = Math.round(16/9*PRECISION)/PRECISION;
	public static var ASPECT_RATIO_4x3:Float = Math.round(4/3*PRECISION)/PRECISION;
	public static var ASPECT_RATIO_3x2:Float = Math.round(3/2*PRECISION)/PRECISION;
	
	inline static var ASPECT_RATIO_STRING_16x9:String = '16x9';
	inline static var ASPECT_RATIO_STRING_4x3:String = '4x3';
	inline static var ASPECT_RATIO_STRING_3x2:String = '3x2';
	inline static var ASPECT_RATIO_STRING_CUSTOM:String = 'custom';
	
	inline static var SCALE_NONE:String = 'none';
	inline static var SCALE_BY_SCALE:String = 'scale';
	inline static var SCALE_BY_DEFINITION:String = 'definition';
	
	private static var _SCALE_METHOD:String = SCALE_BY_SCALE;
	
	private static var _ASPECT_RATIO:Float = ASPECT_RATIO_4x3;
	private static var _ASPECT_RATIO_STRING:String = ASPECT_RATIO_STRING_4x3;
	
	private static var _CONTENT_SCALE:Float = 1;

	public static var SCALE_FACTOR:Float = 1;
	public static var SCALE:Float = 1;
	
	public static var ORIENTATION:String;
	
	public inline static var STANDARD_DEFINITION:String = 'SD';
	public inline static var HIGH_DEFINITION:String = 'HD';
	
	private static var _CONTENT_DEFINITION:String = STANDARD_DEFINITION;
	
	public static var CONTENT_WIDTH:Float = 320;
	public static var CONTENT_HEIGHT:Float = 480;
	
	public static var sharedObject:SharedObject;
	private static var _sharedObjectID:String = '';
	
	public static var supportedContentScales:Array<Float> = [1,2,2.4,4.8];
	
	public static var SCALE_STARLING:Bool = true;

	public static var SOUND_FORMAT:String = 'mp3';
	public static var SOUND_SUFFIX:String = '';

	public static var MOBILE_SUFFIX:String = '';

	public static var MOBILE:Bool;
	
	public static var sharedObjectID(get,set):String;
	public static function get_sharedObjectID():String
	{
		return _sharedObjectID;
	}

	public static function set_sharedObjectID(value:String):String
	{
		_sharedObjectID = value;
		if(_sharedObjectID != ''){
			sharedObject = SharedObject.getLocal(_sharedObjectID);
		}
		return _sharedObjectID;
	}

	public static var SCALE_METHOD(get,set):String;
	public static function get_SCALE_METHOD():String
	{
		return _SCALE_METHOD;
	}

	public static function set_SCALE_METHOD(value:String):String

	{
		if(value == SCALE_NONE || value == SCALE_BY_SCALE || value == SCALE_BY_DEFINITION){
			_SCALE_METHOD = value;
		} else {
			throw('Invalid scale method : '+value);
		}
		return _SCALE_METHOD;
	}

	public static var CONTENT_DEFINITION(get,set):String;
	public static function get_CONTENT_DEFINITION():String
	{
		return _CONTENT_DEFINITION;
	}

	public static function set_CONTENT_DEFINITION(value:String):String
	{
		switch(value){
			
			case STANDARD_DEFINITION :
				_CONTENT_DEFINITION = value;

			case HIGH_DEFINITION :
				_CONTENT_DEFINITION = value;
			
			default :
				trace('Invalid content definition : '+value+'\n'+'Valid content definitions are : STANDARD_DEFINITION or HIGH_DEFINITION');
		}
		return _CONTENT_DEFINITION;
	}

	public static var CONTENT_SCALE(get,set):Float;
	public static function get_CONTENT_SCALE():Float
	{
		return _CONTENT_SCALE;
	}

	public static function set_CONTENT_SCALE(value:Float):Float
	{
		var scaleSupported:Bool = false;
		
		for(i in 0... supportedContentScales.length){
			if(supportedContentScales[i] == value){
				scaleSupported = true;
				break;
			}
		}

		if(scaleSupported){
			_CONTENT_SCALE = value;
		} else {
 			Reflect.callMethod(supportedContentScales, Reflect.field(supportedContentScales, "sort"), []);
			for(i in 0... supportedContentScales.length){
				var thisScale:Float = supportedContentScales[i];
				if(value <= thisScale){
					_CONTENT_SCALE = thisScale;
					break;
				}
			}
		}
		SCALE_FACTOR = value / _CONTENT_SCALE;
		SCALE = SCALE_FACTOR* _CONTENT_SCALE;
		return _CONTENT_SCALE;
	}

	public static var ASPECT_RATIO_STRING(get,never):String;
	public static function get_ASPECT_RATIO_STRING():String

	{
		return _ASPECT_RATIO_STRING;
	}

	public static var ASPECT_RATIO(get,set):Float;
	public static function get_ASPECT_RATIO():Float

	{
		return _ASPECT_RATIO;
	}

	public static function set_ASPECT_RATIO(value:Float):Float
	{
		var aspectRatio:Float = Math.round(value*PRECISION)/PRECISION;

		switch(aspectRatio){
			
			case Globals.ASPECT_RATIO_16x9 :
				_ASPECT_RATIO = ASPECT_RATIO_16x9;
				_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_16x9;
			
			case Globals.ASPECT_RATIO_4x3 :
				_ASPECT_RATIO = ASPECT_RATIO_4x3;
				_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_4x3;
			
			case Globals.ASPECT_RATIO_3x2 :
				_ASPECT_RATIO = ASPECT_RATIO_3x2;
				_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_3x2;
			
			default :

				if(aspectRatio <= ASPECT_RATIO_3x2){
					_ASPECT_RATIO = ASPECT_RATIO_3x2;
					_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_3x2;
				} else if(aspectRatio <= ASPECT_RATIO_4x3){
					_ASPECT_RATIO = ASPECT_RATIO_4x3;
					_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_4x3;
				} else {
					_ASPECT_RATIO = ASPECT_RATIO_16x9;
					_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_16x9;
				}

				// if(aspectRatio > (ASPECT_RATIO_16x9+ASPECT_RATIO_4x3)/2){
				// 	_ASPECT_RATIO = ASPECT_RATIO_16x9;
				// 	_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_16x9;
				// } else if(aspectRatio > (ASPECT_RATIO_3x2+ASPECT_RATIO_4x3)/2){
				// 	_ASPECT_RATIO = ASPECT_RATIO_4x3;
				// 	_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_4x3;
				// } else {
				// 	_ASPECT_RATIO = ASPECT_RATIO_3x2;
				// 	_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_3x2;
				// }
//					_ASPECT_RATIO_STRING = ASPECT_RATIO_STRING_CUSTOM;
//					throw('Invalid aspect ratio : '+value+'\n'+
//						'Valid aspect ratios are : '+ASPECT_RATIO_16x9+', '+ASPECT_RATIO_4x3+', '+ASPECT_RATIO_3x2);
		}
		return _ASPECT_RATIO;
	}
	
	public static function parseXmlVariables(xml:Xml, object:Dynamic, _globalsClass:String='haxeframe.Globals'):Xml
	{
		var _globals:Class<Dynamic> = Type.resolveClass(_globalsClass);

		var c:Class<Dynamic> = Type.getClass(object);
		var instanceFields:Array<String> = Type.getInstanceFields(c);
		
		var configString:String = xml.toString();
		var configParts:Array<String> = configString.split('$[');
		
		if(configParts.length > 1){
			
			var newString:String = configParts[0];
			
			for(p in 1...configParts.length){
				var partParts:Array<String> = configParts[p].split(']$');
				var varName:String = partParts[0];
				var isColor:Bool = false;

				if(varName.toLowerCase().indexOf('color') >= 0){
					isColor = true;
				}

				var value:Dynamic;

				if(Utils.valueInArray(varName, instanceFields) || Utils.valueInArray('set_'+varName, instanceFields)){
					
					value = Reflect.getProperty(object,varName);
					
					if(isColor){
						newString += StringTools.hex(value);
					} else {
						newString += value;
					}
					
				} else if(Reflect.hasField(_globals, varName) || Reflect.hasField(_globals, 'get_'+varName)){

					value = Reflect.getProperty(_globals,varName);

					if(isColor)
						newString += StringTools.hex(value);
					else
						newString += value;
					
				} else if(Reflect.hasField(object, 'stage')){
					
					var thisStage:Dynamic = Reflect.getProperty(object, 'stage');

					if(Reflect.hasField(thisStage, varName) || Reflect.hasField(thisStage, 'get_'+varName)){

						value = Reflect.field(thisStage,varName);

						if(isColor)
							newString += StringTools.hex(value);
						else
							newString += value;
						
					} else {
						
						newString += '$['+varName+']$';
					}
				} else {

					newString += '$['+varName+']$';
				}
				
				newString += partParts[1];
			}
			xml = Xml.parse(newString);
		}
		return xml;
	}

}